<?php

namespace App\service\nft;

use Exception;
use support\Log;
use support\Redis;
use think\facade\Db;
use crmeb\exceptions\AdminException;
use think\db\exception\{DataNotFoundException, DbException, ModelNotFoundException};

class BatchDropServices
{
    /**
     * 黑洞账号 空投藏品
     * @param array $data
     * @return float|int
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function blackHoleDrop(array $data)
    {
        $prefix = env('REDIS_PREFIX');
        $ttl_seconds = env('REDIS_TTL_SECONDS');

        $goods_id = $data['goods_id']; // 选择的要空投的藏品id
        $num = $data['num']; // 选择的要空投的藏品数量
//        $condition = $data['condition']; // 空投条件
        $desc = $data['desc']; // 定向空投 人员  目前是单个手机号
        $date1 = $data['date1']; // 空投时间 年月日
        $date2 = $data['date2']; // 空投时间 时分秒

        # 批量空投表 数据
        $batchDropSqlData = [
            'goods_id' => $goods_id, // 空投的藏品id
            'num' => $num, // 数量
            'drop_time' => $date1 . ' ' . $date2 // 空投时间
        ];

        # 批量空投条件
        $batch_drop_conditions = [];

        $user_info_columns = []; // 满足条件的空投人员 用户id列表 包含 account_id

        $batch_drop_user = []; // 批量空投人员明细表

        # 开始求出 空投人员
        foreach ($desc as $v) {
            if (!$this->cmf_check_mobile($v)) {
                throw new AdminException('手机号' . $v . '格式不正确！');
            }
            $item_user = [
                'mobile' => $v,
                'user_id' => null,
                'account_id' => null,
            ];
            $userInfo = Redis::get($prefix . 'user_mobile_' . $v);
            if ($userInfo) {
                $userInfo = json_decode($userInfo, true);
                if ($userInfo['account_id']) {
                    $user_info_columns[] = [
                        'user_id' => $userInfo['user_id'],
                        'mobile' => $userInfo['mobile'],
                        'account_id' => $userInfo['account_id'],
                    ];
                    if (!isset($item_user['is_conditions'])) {
                        $item_user['is_conditions'] = 1;
                        $item_user['desc'] = '此手机号当前满足空投条件';
                    }
                    $item_user['user_id'] = $userInfo['user_id'];
                    $item_user['account_id'] = $userInfo['account_id'];
                }
            }
            if (!isset($item_user['is_conditions'])) {
                $item_user['is_conditions'] = 0;
                $item_user['desc'] = '此手机号暂未注册区块链链账户地址';
            }
            $batch_drop_user[] = $item_user;
        }
        # 拿到空投人员数组
        if (!$user_info_columns) {
            throw new AdminException('所填空投人员没有一个是满足空投条件的（不存在或者是未注册区块链链账户地址）！');
        }

        $dateTime = strtotime($date1 . ' ' . $date2);
        $batch_drop_log = []; // 批量空投明细

        $goodsInfo = Db::name('goods')->where('id', $goods_id)->find();

        $fa_count = count($user_info_columns) * $num;

        $ttl_seconds = 3600 * 3;
        $key = $prefix . $goods_id . '_ex_goods_id_num';

        $have = Redis::get($key); // 查看redis库存

        if ($have === false) {
            throw new AdminException('暂未开启redis缓存！');
        }

        if ($have <= 0) {
            throw new AdminException('库存不足！');
        }

        if ($have < $fa_count) {
            throw new AdminException('当前库存不足！(库存：' . $have . '份,准备空投：' . $fa_count . '份)');
        }

        Redis::watch($key); // 乐观锁 监视作用 set() 初始值0
        $stock = Redis::get($key);

        if ($stock === null) {
            throw new AdminException('redis库存暂未开启！');
        }

        if ($stock === '0') {
            throw new AdminException('库存不足！');
        }

        // 开启事务
        Redis::multi();
        Redis::decrBy($key, $fa_count); // 将 key 中 储存的数字值增一，如果key不存在，那么key的值会先被初始化为0，然后再执行 incr操作
        $res = Redis::exec(); // 成功1 失败0

        if (isset($res[0]) && $res[0] >= 0) {
            // 秒杀成功

            $uid = $user_info_columns[0]['user_id'];
            $mobile = $user_info_columns[0]['mobile'];
            $account_id = $user_info_columns[0]['account_id'];

            $find = Db::name('nft')->where('uid', $uid)->where('goods_id', $goods_id)->find();

            //开始事务
            Db::startTrans();

            try {

                //            $key = $prefix . $goods_id . '_ex_goods_id_num';
                // 编号 key redis计数
                $value_key = $prefix . 'goods_' . $goods_id . '_number';

                # 减库存
                if (!Db::name('goods')->where('id', $goods_id)->dec('current_have_num', $fa_count)->update()) {
                    throw new AdminException("网络错误请稍后重试！");
                }

                // 加已售数量
                if (!Db::name('goods')->where('id', $goods_id)->inc('sold', $fa_count)->update()) {
                    throw new AdminException("网络错误请稍后重试！");
                }

                if (!$find) {
                    $nft_pk_id = Db::name('nft')->insertGetId([
                        'uid' => $uid,
                        'mobile' => $mobile,
                        'account_id' => $account_id,
                        'goods_id' => $goods_id,
                        'goods_name' => $goodsInfo['name'],
                        'created_at' => date('Y-m-d H:i:s'),
                        'updated_at' => date('Y-m-d H:i:s')
                    ]);
                } else {
                    $nft_pk_id = $find['id'];
                    Db::name('nft')->where('id', $nft_pk_id)->update(['updated_at' => date('Y-m-d H:i:s')]);
                }

                for ($i = 0; $i < $fa_count; $i++) {
                    $value = Redis::incrBy($value_key, 1);
                    // 开始创建nft_list记录
                    if (!Db::name('nft_list')->insert([
                        'nft_pk_id' => $nft_pk_id,
                        'uid' => $uid,
                        'goods_id' => $goods_id,
                        'name' => $goodsInfo['name'],
                        'value' => $value,
                        'pic' => $goodsInfo['pic'],
                        'hash' => $goodsInfo['pic_hash'],
                        'prev_get_drop_time' => date('Y-m-d H:i:s'),
                        'created_at' => date('Y-m-d H:i:s'),
                        'updated_at' => date('Y-m-d H:i:s')
                    ])) {
                        throw new AdminException("网络错误请稍后重试！");
                    }
                }

                // 提交事务
                Db::commit();
            } catch (\Exception $e) {
                // 回滚事务
                Db::rollback();
                Redis::incrBy($key, $fa_count);
                throw new AdminException($e->getMessage());
            }

            return $fa_count;
        } else {
            throw new AdminException("黑洞空投失败，没抢到！");
        }
    }

    public function cmf_check_mobile($mobile)
    {
        if (preg_match('/(^(13\d|14\d|15\d|16\d|17\d|18\d|19\d)\d{8})$/', $mobile)) {
            return true;
        } else {
            if (preg_match('/^\d{1,4}-\d{5,11}$/', $mobile)) {
                if (preg_match('/^\d{1,4}-0+/', $mobile)) {
                    //不能以0开头
                    return false;
                }

                return true;
            }

            return false;
        }
    }
}
